package com.dnb.webmash.playmaker.shared;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashSet;

import javax.jdo.annotations.Embedded;
import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.datastore.Text;
import com.google.gwt.user.client.rpc.IsSerializable;


/*
 * A node in a playlist
 */
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class PlaylistItem implements IsSerializable{
	@Persistent
	@Embedded
	private MyURL myURL;
	@Persistent
	private String mediaID, name, owner, mediaType;	
	@Persistent	
	private PlayerType playerType;
	@Persistent
	private Date createDate;
	@Persistent
	private boolean isPlayable = false;
	@PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
    private String primaryKey;
	@Persistent
	private Text element, parents;
	@Persistent
	private ArrayList<String> tags;
	@NotPersistent
	private LinkedHashSet<PlaylistItem> children;
	@NotPersistent
	private ArrayList<PlaylistItem> nextLevel=null;
	
	public PlaylistItem(){
		this.createDate = new Date();
	}
	public PlaylistItem(String myurl, String mediaId){//media node
		this();
		this.myURL = new MyURL(myurl+mediaId);
		this.mediaID = mediaId;
	}
	public PlaylistItem(String name){//a placeholder node or media node
		this();
		this.name = name;
	}
	public PlaylistItem(MyURL address){//link node
		this();
		this.myURL = address;
	}
	public PlaylistItem(MyURL address, String name){//link node with name
		this();
		this.myURL = address;
		this.name = name;
	}

	public LinkedHashSet<PlaylistItem> getChildren() {
		if (this.children==null) this.children = new LinkedHashSet<PlaylistItem>();
		return children;
	}
	public String getName() {
		if (name!=null)	return name;
		else return this.getFullURL();
	}
	public boolean setName(String nName){
		if (name==null){
			this.name = nName;
			return true;
		}
		return false;
	}
	public String getFullURL() {
		if (myURL!=null)
			return this.myURL.toString();
		else return null;
	}	
	public boolean hasChildren() {
		if (this.children==null) return false;
		if (this.children.isEmpty())return false;
		return true;
	}
	public boolean isSkeleton(){
		return (myURL==null)&&(mediaID==null)&&(name==null)&&(children==null)&&(element==null);
	}
	/*
	 * Adds the playlistitem if it is not contained in the children or replaces its equivalent if it has more grandchildren than it
	 */
	public boolean addChild(PlaylistItem it) {
		if (this.children==null) this.children = new LinkedHashSet<PlaylistItem>();
		return this.children.add(it);
	}
	
	public boolean addChildren(LinkedHashSet<PlaylistItem> children2) {
		if (this.children==null) this.children = new LinkedHashSet<PlaylistItem>();
		return this.children.addAll(children2);		
	}

	public boolean removeChild(PlaylistItem child) {
		if (this.children==null) return false;
		else return this.children.remove(child);
	}	
	public ArrayList<PlaylistItem> getNextLevel() {
		return nextLevel;
	}
	public void addToNextLevel(ArrayList<PlaylistItem> nL) {
		if (this.nextLevel == null)
			this.nextLevel = new ArrayList<PlaylistItem>(nL);
		else this.nextLevel.addAll(nL);
		//this.nextLevel = new ArrayList<PlaylistItem>(nextLevel);
	}
	public boolean setPlayable(boolean setP) { return this.isPlayable = setP; }
	
	public boolean isPlayable() { return this.isPlayable;}

	public PlayerType getPlayerType() {
		return this.playerType;
	}
	public void setPlayerType(PlayerType playerType2) {
		this.playerType = playerType2;
	}
	public String getMediatype() {
		return mediaType;
	}
	public void setMediatype(String mediatype) {
		this.mediaType = mediatype;
	}
	public void setElement(String el){
		this.element = new Text(el);
	}
	public String getElement() {
		return this.element.getValue();
	}
	public Text getParents() {
		return parents;
	}
	public void setParents(Text parents) {
		this.parents = parents;
	}
	public MyURL getURL() {
		return myURL;
	}
	public String getOwner() {
		return owner;
	}
	public void setOwner(String owner) {
		this.owner = owner;
	}		
	public Date getCreateDate() {
		return createDate;
	}
	public void setCreateDate(Date createDate) {
		this.createDate = createDate;
	}
	public String getEncodedKey() {
		return primaryKey;
	}
	public void setTags(ArrayList<String> tags) {
		this.tags = tags;
	}
	public ArrayList<String> getTags() {
		return tags;
	}
	public Boolean addTag(String tag){
		return tags.add(tag);
		
	}
	@Override
	public String toString() {
		return "PlaylistItem [myURL=" + myURL + ", mediaID=" + mediaID
				+ ", name=" + name + ", owner=" + owner + ", mediatype=" + playerType
				+ ", createDate=" + createDate + ", isPlayable=" + isPlayable
				+ ", primaryKey=" + primaryKey + ", element=" + element
				+ ", children=" + children + "]";
	}
	public String toPrettyString() {
		return "[name=" + name + "\nmediaID=" + mediaID
		+ "myURL=" + myURL + "\nowner=" + owner + "\nmediaType=" + playerType
		+ "\ncreateDate=" + createDate + "\nisPlayable=" + isPlayable
		+ "\nencodedKey=" + primaryKey + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (isPlayable ? 1231 : 1237);
		if (!isPlayable) { // This leaves the hashcode for playable items tbd only by isPlayable (want to put all playableitems in one bucket)
			result = prime * result
			+ ((children == null) ? 0 : children.size());//using the number of children as a hashcode instead of arraylist.hashcode()			
			result = prime * result + ((mediaID == null) ? 0 : mediaID.hashCode());
			result = prime * result + ((myURL == null) ? 0 : myURL.hashCode());
			result = prime * result + ((name == null) ? 0 : name.hashCode());
			result = prime * result + ((playerType == null) ? 0 : playerType.hashCode());
		}
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;		
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		PlaylistItem other = (PlaylistItem) obj;				
				
		if (isPlayable != other.isPlayable)
			return false;
		
		if (myURL == null) { // Check first for URL equality, only for playableitems use a hedged-equality to prevent duplicates
			if (other.myURL != null)
				return false;
		} else {
			if (this.isPlayable){
				//if either URL is equal or contained in the other return true (see def of myURL.compareTo)
				if ((myURL.compareTo(other.myURL)<=0)||(other.myURL.compareTo(myURL)<=0)) return true; 
			} 
			if (!myURL.equals(other.myURL))
				return false;
		}
		//Compare everything else except for createdate, owner, and primarykey						
		if (element == null) {
			if (other.element != null)
				return false;
		} else if (!element.equals(other.element))
			return false;
		else if (element.equals(other.element)) return true; //break here we dont care about the rest
		if (mediaID == null) {
			if (other.mediaID != null)
				return false;
		} else if (!mediaID.equals(other.mediaID))
			return false;
		else if (mediaID.equals(other.mediaID)) return true; //break here
		if (children == null) {
			if (other.children != null)
				return false;
		} else if (!children.equals(other.children))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		//TODO add mediatype or playertype comparisons here?
		return true;
	}
}